package com.hans.scala

/**
 * 样本类 模式匹配
 * Created by Hans on 2014/4/4.
 */
object CaseAndMatchExample {

  def main(args: Array[String]) {
    //    test1()
    //    test2()
    test3()

  }

  //用作偏函数的样本序列
  def test3() {
    println("用作偏函数的样本序列：")
    def withDefault: Option[Int] => Int = {
      case Some(x) => x
      case None => 0
    }
    println(withDefault(Some(3)))
    println(withDefault(None))

    def second: PartialFunction[List[Int], Int] = {
      case x :: y :: _ => y
    }
    /**
     * Warning:(100, 37) match may not be exhaustive.
     * It would fail on the following input: List(_)
     */
//    def second2: List[Int] => Int = {
//      case x :: y :: _ => y
//    }
//    println(second(List()))
//    println(second2(List()))

    //    def p1: PartialFunction[Int, Int] = {
    //      case x if x > 1 => 1
    //    }
    //
    //    def p2 = (x: Int) => x match {
    //      case x if x > 1 => 1
    //    }
    //
    //    println(p1(-1))
    //    println(p2(-1))

  }

  def test1() {
    def simplify(expr: Expr) = expr match {
      case UpOp("-", UpOp("-", e)) => e
      case BinOp("+", e, Number(0)) => e
      case BinOp("*", e, Number(1)) => e
      case _ => expr
    }

    val v = new Var("x")
    val op = new BinOp("+", Number(1), v)

    println(op)
    println(UpOp("-", UpOp("-", v)))
    println(simplify(UpOp("-", UpOp("-", v))))

    println("\n\n模式守卫：")
    def simplifyAdd(expr: Expr) = expr match {
      case BinOp("+", x, y) if x == y => BinOp("*", x, Number(2)) //case BinOp("+", x, y) => if (x == y) BinOp("*", x, Number(2))
      case _ => expr
    }
    println(simplifyAdd(BinOp("+", Number(3), Number(3))))
    println(simplifyAdd(BinOp("+", Number(4), Number(3))))
    println(simplifyAdd(BinOp("-", Number(4), Number(3))))
  }

  //封闭类
  def test2() {
    println("封闭类：")

    /**
     * 会有警告，潜在运行期故障
     * It would fail on the following inputs: BinOp(_, _, _), UpOp(_, _)
     * def describe(expr: Expr): String = expr match {
     */
    //    def describe(expr: Expr): String = expr match {
    //      case Number(_) => "a is number"
    //      case Var(_) => "a is variable"
    //    }

    /**
     * 去掉警告
     */
    //    def describe(expr: Expr): String = (expr: @unchecked) match {
    //      case Number(_) => "a is number"
    //      case Var(_) => "a is variable"
    //    }
  }

  //封闭类
  sealed abstract class Expr

  case class Var(name: String) extends Expr {
    override def toString = name
  }

  case class Number(num: Double) extends Expr {
    override def toString = num.toString
  }

  case class UpOp(operator: String, arg: Expr) extends Expr {
    override def toString = operator + " " + arg.toString
  }

  case class BinOp(operator: String, left: Expr, right: Expr) extends Expr {
    override def toString = left.toString + " " + operator + " " + right.toString
  }


}
